import axios from "axios"
import type { AxiosRequestConfig, AxiosResponse } from 'axios'
import local from "./local"
import { _login, _logout } from '@/api/login/login'
import { ElMessage } from 'element-plus'
import router from '../router'
// 声明一个 Map 用于存储每个请求的标识 和 取消函数
const pending = new Map()
class HttpRequest {
  baseUrl: string
  pending: {}
  constructor(baseUrl: string) {
    this.baseUrl = baseUrl
    this.pending = {}
  }
  // 获取axios配置
  getAxiosConfig() {
    const config = {
      baseURL: this.baseUrl,
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      },
      timeout: 1000 * 60 * 10,
      // crossDomain: true,//设置cross跨域
      // withCredentials: true//设置cross跨域 并设置访问权限 允许跨域携带cookie信息
    }
    return config;
  }
  // 取消重复请求
  removePending(config: AxiosRequestConfig) {
    const url = [
      config.method,
      config.url,
      config.params,
      config.data
    ].join('&')
    if (pending.has(url)) { // 如果在 pending 中存在当前请求标识，需要取消当前请求，并且移除
      const cancel = pending.get(url)
      cancel(url)
      pending.delete(url)
    }
  }
  // 添加请求
  addPending(config: AxiosRequestConfig) {
    const url = [
      config.method,
      config.url,
      config.params,
      config.data
    ].join('&')
    config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
      if (!pending.has(url)) { // 如果 pending 中不存在当前请求，则添加进去
        pending.set(url, cancel)
      }
    })
  }
  // 清空 pending 中的请求（在路由跳转时调用）
  clearPending() {
    for (const [url, cancel] of pending) {
      cancel(url)
    }
    pending.clear()
  }
  // 刷新token
  async resetToken() {
    let tokenObj = local.get('tokenObj');
    let res = await _login({
      grantType: 'refresh_token',
      refreshToken: tokenObj?.refreshToken || ''
    })
    if (!res) {
      this.loginout()
    }
  }
  loginout() {
    local.remove('tokenObj')
    router.replace('/login')
  }
  // 拦截器
  interceptors(instance: any) {
    // 请求拦截器
    instance.interceptors.request.use(
      (config: any) => {
        this.removePending(config);// 在请求开始前，对之前的请求做检查取消操作
        this.addPending(config);// 将当前请求添加到 pending 中
        const { url, headers } = config
        let tokenObj = local.get('tokenObj');
        const filterArr = ['/oauth/token']
        tokenObj || !filterArr.includes(url) ? headers.Authorization = `${tokenObj.tokenHead}${tokenObj.token}` : headers.Authorization = 'Basic Y3VybF9jbGllbnQ6c2VjcmV0'
        return config;
      }, (error: any) => {
        error.data = {};
        error.data.msg = '服务器异常，请联系管理员！';
        return Promise.resolve(error);
      }
    )
    // 响应拦截器
    instance.interceptors.response.use(
      (response: AxiosResponse) => {
        this.removePending(response.config); // 在请求结束后，移除本次请求
        const status = response.status;
        if (status === 200) {
          const { code, data, message } = response.data
          if (!code) return Promise.resolve(response.data)
          // 文件流返出错误信息
          // if (!code && showName) return Promise.resolve({ data: res.data, name: res.headers['content-disposition'] })
          switch (String(code)) {
            case '-10000':
              return Promise.resolve(response.data)
            case '-10002':
              this.resetToken()
              break
            case '10000':
              return data ? Promise.resolve(response.data) : Promise.resolve(message)
            case '-50000':
              ElMessage.error(message ?? '服务器未知错误,请稍后再试...')
              break
            case '200':
              return Promise.resolve(response.data)
            default:
              ElMessage.warning(message || '获取数据失败')
              break
          }
          // 续签TOKEN
          // if (response.headers && response.headers.authorization) {
          //   let str = response.headers.authorization?.slice(7)
          //   let tokenObj = {
          //     expiresIn: 17543,
          //     refreshToken: str,
          //     token: str,
          //     tokenHead: "Bearer ",
          //   }
          //   local.set('tokenObj', JSON.stringify(tokenObj))
          // }
          // return response
        } else if (response.status === 401) {
          this.loginout()
        } else {
          return Promise.reject(response)
        }
      }
    )
  }
  // 创建实例
  request(options: any) {
    const instance = axios.create()
    const newOptions = Object.assign(this.getAxiosConfig(), options)
    this.interceptors(instance)
    return instance(newOptions)
  }
  //get 
  get(url: string, headers = {}) {
    return this.request(
      Object.assign(
        {
          method: 'get',
          url
        },
        headers
      )
    )
  }
  // post
  post(url: string, data?: any, headers?: any) {
    return this.request({
      method: 'post',
      headers,
      url,
      data,
    })
  }
  // post文件请求
  postFile(url: string, data?: any, headers?: any) {
    return this.request({
      method: 'post',
      headers,
      url,
      data,
      responseType: "blob"
    })
  }
  //put
  put(url: string, config = {}) {
    return this.request(
      Object.assign(
        {
          method: 'put',
          url
        },
        config
      )
    )
  }
  // delete
  delete(url: string, data: any = null, config = {}) {
    return this.request(
      Object.assign(
        {
          method: 'delete',
          url,
          data: data
        },
        config
      )
    )
  }
}
export default HttpRequest